﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml.Linq;
using MaxZhang.EasyEntities.Attribute;
using MaxZhang.EasyEntities.Dynamic.Aop.Exception;

namespace MaxZhang.EasyEntities.Dynamic.Aop
{
    /// <summary>
    /// 配制文件加载类
    /// </summary>
    public class Config
    {
        public Config(string filename,Assembly ass)
        {
            this._filename = filename;
            assembly=ass;
            if(assembly==null)
                assembly = Assembly.GetEntryAssembly();     //(exe)主程序的程序集
            _aspList = new List<AopAspectInfo>(20);
        }


        private string _filename;
        private List<AopAspectInfo> _aspList=null;
        private Assembly assembly=null;

        
        public string FileName
        {
            get
            {
                return _filename;
            }
        }

        /// <summary>
        /// 从配制文件中加载拦截器
        /// </summary>
        /// <param name="filename">文件名</param>
        public void Load()
        {
           
            AopTabel.Aspects.Clear();                           //清空AOP表中的拦截器
            XElement doc = null;
            try
            {
                doc = XElement.Load(_filename);
                LoadAspectList(doc);                            //载入XML中的AOP拦截器
                LoadClasses(doc);                               //载放XML中所有类、方法和拦截器信息
            }
            catch(System.Exception ex)
            {
                throw new AopConfigException("AOP配置文件解析错误!"+ ex.Message);
            }
            finally
            {
                doc = null;
            }
        }
        

        /// <summary>
        ///从XML中载入类型列表及类中的方法和拦截器 
        /// </summary>
        /// <param name="doc">XML根节点</param>
        private void LoadClasses(XElement doc)
        {
            var application = doc.Element("Application");
            if (application == null)
                throw new AopConfigException("载入时错误,文档中没有Application子元素");


            var classList= application.Descendants("Class");
                
            foreach (var c in classList)
            {
                if(c.Attribute("name")==null)
                    throw new AopConfigException("载入时错误,Class元素中没有name属性!");
                string cName= c.Attribute("name").Value;
                AopClassInfo cInfo = new AopClassInfo(cName);
                LoadClassOfMethods(c, cInfo);
                AopTabel.Aspects.ClassList.Add(cInfo);
            }
        }

        /// <summary>
        /// 从XML中载入类中的方法列表和拦截器
        /// </summary>
        /// <param name="c">类型列表XML描述</param>
        /// <param name="cInfo">AOP类信息</param>
        private void LoadClassOfMethods(XElement c, AopClassInfo cInfo)
        {
            var methodList = c.Descendants("Method");
            foreach (var m in methodList)
            {
                if (m.Attribute("name") == null)
                    throw new AopConfigException("载入时错误,Method元素中没有name属性!");
                string mName = m.Attribute("name").Value;
                AopMethodInfo mInfo = new AopMethodInfo(mName);

                LoadMethodAspect(m, mInfo);
                cInfo.AddMethodInfo(mInfo);
            }
        }



        /// <summary>
        /// 从XML中载入方法列表和拦截器
        /// </summary>
        /// <param name="m">方法列表XML描述</param>
        /// <param name="mInfo">AOP方法信息</param>
        private void LoadMethodAspect(XElement m, AopMethodInfo mInfo)
        {
         
            var aspectlist = m.Descendants("Aspect");
            foreach (var a in aspectlist)
            {
                string aspectId= a.Attribute("id").Value;
                var interceptor = (from asp in _aspList 
                                  where asp.Id==aspectId
                                  select asp.Interceptor).FirstOrDefault();
                mInfo.AddAspectInfo(aspectId, interceptor);

            }
        }



        /// <summary>
        /// 载入XML中的AOP拦截器
        /// </summary>
        /// <param name="doc">XML中AspectList节点</param>
        private void LoadAspectList(XElement doc)
        {

            var aspectList = doc.Element("Interceptors");
            if (aspectList == null)
                throw new AopConfigException("载入时错误,文档中没有AspectList子元素");
            var plist= aspectList.Descendants("Aspect");
                

            foreach (var p in plist)
            {
                var t_aspect = new AopAspectInfo();
                string id = p.Attribute("id").Value;
                string typename = p.Attribute("type").Value;
                t_aspect.Id=id;
                    
                t_aspect.Interceptor = (InterceptorBaseAttribute)assembly.CreateInstance(typename); ;
                _aspList.Add(t_aspect);
            }
        }
    }
}
